package com.smart.service.impl;

import com.smart.global.GlobalWord;
import com.smart.pojo.*;
import com.smart.resp.*;
import com.smart.service.*;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class IProcessServiceImpl implements IProcessService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ILeaveBillService leaveBillService;

    @Autowired
    private IReimbursementBillService reimbursementBillService;

    @Autowired
    private IResignBillService resignBillService;

    @Autowired
    private IUserService userService;

    @Autowired
    IConceptualProductService conceptualProductService;
    @Autowired
    IOutboundBillService outboundBillService;

    @Override
    public List<TaskInfo> queryTaskByUserId(Long userId) {
        //根据用户组查询(该操作需要SpringSecurity支持，不然报异常)
        List<Task> list = taskService.createTaskQuery()
                .taskCandidateUser(userId.toString())
                .list();
        //根据Assignee查询
        List<Task> list1 = taskService.createTaskQuery()
                .taskAssignee(userId.toString())
                .list();
        //将两个任务集合合并返回
        list.addAll(list1);

        List<TaskInfo> taskInfos = new ArrayList<>();
        for (Task task : list) {
            if (task.getName().equals("确认研发部门") || task.getName().equals("交付成品")) {
                continue;
            }
            TaskInfo taskInfo = new TaskInfo();
            taskInfo.setTaskId(task.getId());
            taskInfo.setTaskName(task.getName());
            taskInfo.setCreateTime(task.getCreateTime());
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
            Deployment deployment = repositoryService.createDeploymentQuery().processDefinitionKey(processDefinition.getKey()).singleResult();
            taskInfo.setName(deployment.getName());
            String businessKey = getBusinessKeyByTaskId(task.getId());
            String billId = businessKey.split("\\.")[1];
            String billType = businessKey.split("\\.")[0];
            if (billType.equalsIgnoreCase(GlobalWord.LEAVE_KEY)) {
                LeaveBillResp leaveBillResp = leaveBillService.queryByBillId(Long.parseLong(billId));
                taskInfo.setApplyUserId(leaveBillResp.getUserId());
                taskInfo.setApplyUsername(leaveBillResp.getUsername());
            } else if (billType.equalsIgnoreCase(GlobalWord.REIMBURSEMENT_KEY)) {
                ReimbursementBillResp reimbursementBillResp = reimbursementBillService.queryByBillId(Long.parseLong(billId));
                taskInfo.setApplyUserId(reimbursementBillResp.getUserId());
                taskInfo.setApplyUsername(reimbursementBillResp.getUsername());
            } else if (billType.equalsIgnoreCase(GlobalWord.DEVELOPED_KEY)) {
                ConceptualResp conceptualResp = conceptualProductService.queryByBillId(Long.parseLong(billId));
                taskInfo.setApplyUserId(conceptualResp.getUserId());
                taskInfo.setApplyUsername(conceptualResp.getUsername());
            } else if (billType.equalsIgnoreCase(GlobalWord.OUTBOUND_KEY)) {
                OutboundBillResp outboundBillResp = outboundBillService.queryByBillId(Long.parseLong(billId));
                taskInfo.setApplyUserId(outboundBillResp.getUserId());
                taskInfo.setApplyUsername(outboundBillResp.getUsername());
            } else if (billType.equalsIgnoreCase(GlobalWord.RESIGN_KEY)) {
                ResignBillResp resignBillResp = resignBillService.queryByBillId(Long.parseLong(billId));
                taskInfo.setApplyUserId(resignBillResp.getUserId());
                taskInfo.setApplyUsername(resignBillResp.getUsername());
            }

            taskInfos.add(taskInfo);
        }
        return taskInfos;
    }

    @Override
    public String getBusinessKeyByTaskId(String taskId) {
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .singleResult();
        return processInstance.getBusinessKey();
    }

    @Override
    public TaskForm viewTaskForm(String taskId) {
        //获取唯一标识businessKey，从而判断当前任务属于哪个申请流程
        String businessKey = getBusinessKeyByTaskId(taskId);
        String billType = businessKey.split("\\.")[0];
        String billId = businessKey.split("\\.")[1];
        TaskForm taskForm = new TaskForm();
        taskForm.setBillType(billType);

        //判断当前任务节点关联的申请单类型
        if (billType.equalsIgnoreCase(GlobalWord.LEAVE_KEY)) {
            LeaveBillResp leaveBillInfo = leaveBillService.queryByBillId(Long.parseLong(billId));
            taskForm.setBillInfo(leaveBillInfo);
        } else if (billType.equalsIgnoreCase(GlobalWord.REIMBURSEMENT_KEY)) {
            ReimbursementBillResp reimbursementBillResp = reimbursementBillService.queryByBillId(Long.parseLong(billId));
            taskForm.setBillInfo(reimbursementBillResp);
        } else if (billType.equalsIgnoreCase(GlobalWord.DEVELOPED_KEY)) {
            ConceptualResp conceptualResp = conceptualProductService.queryByBillId(Long.parseLong(billId));
            taskForm.setBillInfo(conceptualResp);
        } else if (billType.equalsIgnoreCase(GlobalWord.OUTBOUND_KEY)) {
            OutboundBillResp outboundBillResp = outboundBillService.queryByBillId(Long.parseLong(billId));
            taskForm.setBillInfo(outboundBillResp);
        } else if (billType.equalsIgnoreCase(GlobalWord.RESIGN_KEY)) {
            ResignBillResp resignBillResp = resignBillService.queryByBillId(Long.parseLong(billId));
            taskForm.setBillInfo(resignBillResp);
        }

        //获取关联的批注信息列表
        List<CommentData> commentDataList = queryAllCommentByTaskId(taskId);
        taskForm.setComments(commentDataList);
        //获取当前任务可执行的命令
        List<String> sequenceList = querySequenceListByTaskId(taskId);
        taskForm.setSequenceList(sequenceList);

        return taskForm;
    }

    @Override
    public TaskForm auditTrail(String billType, Long id) {
        //根据businessKey获取历史流程实例
        String businessKey = billType + "." + id;
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .singleResult();
        TaskForm taskForm = new TaskForm();
        //获取关联的批注信息列表
        List<CommentData> commentDataList = queryAllCommentByHistoryProcessInstanceId(historicProcessInstance.getId());
        taskForm.setComments(commentDataList);

        //判断当前任务节点关联的申请单类型
        if (billType.equalsIgnoreCase(GlobalWord.LEAVE_KEY)) {
            LeaveBillResp leaveBillInfo = leaveBillService.queryByBillId(id);
            taskForm.setBillInfo(leaveBillInfo);
        } else if (billType.equalsIgnoreCase(GlobalWord.REIMBURSEMENT_KEY)) {
            ReimbursementBillResp reimbursementBillResp = reimbursementBillService.queryByBillId(id);
            taskForm.setBillInfo(reimbursementBillResp);
        } else if (billType.equalsIgnoreCase(GlobalWord.DEVELOPED_KEY)) {
            ConceptualResp conceptualResp = conceptualProductService.queryByBillId(id);
            taskForm.setBillInfo(conceptualResp);
        } else if (billType.equalsIgnoreCase(GlobalWord.OUTBOUND_KEY)) {
            OutboundBillResp outboundBillResp = outboundBillService.queryByBillId(id);
            taskForm.setBillInfo(outboundBillResp);
        } else if (billType.equalsIgnoreCase(GlobalWord.RESIGN_KEY)) {
            ResignBillResp resignBillResp = resignBillService.queryByBillId(id);
            taskForm.setBillInfo(resignBillResp);
        }

        return taskForm;
    }

    @Override
    public Task getTaskByBusinessKey(String businessKey) {
        return taskService.createTaskQuery()
                .processInstanceBusinessKey(businessKey)
                .singleResult();
    }

    @Override
    @Transactional
    public boolean deleteByTaskId(String taskId) {
        //获取任务对象
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        //获取流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .singleResult();
        //获取唯一标识businessKey
        String businessKey = processInstance.getBusinessKey();
        String applyType = businessKey.split("\\.")[0];
        Long id = Long.parseLong(businessKey.split("\\.")[1]);

        //删除流程实例，先删除runtime，再删除history，顺序不能错
        runtimeService.deleteProcessInstance(task.getProcessInstanceId(), "");
        historyService.deleteHistoricProcessInstance(task.getProcessInstanceId());

        //处理相关申请单的数据
        if (applyType.equalsIgnoreCase(GlobalWord.RESIGN_KEY)){
            boolean rs = resignBillService.removeById(id);
        }

        return true;
    }

    public List<String> querySequenceListByTaskId(String taskId) {
        // 获取当前任务
        Task task = getTaskByTaskId(taskId);
        //获取当前模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        // 获取当前节点
        FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
        UserTask userTask = (UserTask) flowElement;
        //获取节点出口连线集合
        List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
        //获取连线集合的名称集合
        List<String> collect = outgoingFlows.stream()
                .map(e -> e.getName() == null ? "通过" : e.getName())
                .collect(Collectors.toList());

        return collect;
    }

    private List<CommentData> queryAllCommentByTaskId(String taskId) {
        List<Comment> comments = taskService.getProcessInstanceComments(getTaskByTaskId(taskId).getProcessInstanceId());
        return getCommentDataList(comments);
    }

    private List<CommentData> queryAllCommentByHistoryProcessInstanceId(String historyProcessInstanceId) {
        List<Comment> comments = taskService.getProcessInstanceComments(historyProcessInstanceId);
        return getCommentDataList(comments);
    }

    private List<CommentData> getCommentDataList(List<Comment> comments) {
        List<CommentData> commentDataList = new ArrayList<>();
        for (Comment comment : comments) {
            CommentData commentData = new CommentData(comment.getUserId(), comment.getTime(), comment.getFullMessage());
            UserResp userResp = userService.queryById(comment.getUserId());
            commentData.setUsername(userResp.getUsername());
            commentData.setPic(userResp.getPic());
            commentData.setRoleName(userResp.getRoleName());
            commentDataList.add(commentData);
        }
        return commentDataList;
    }

    private ProcessInstance getProcessInstanceByTaskId(String taskId) {
        Task task = getTaskByTaskId(taskId);
        return runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
    }

    private Task getTaskByTaskId(String taskId) {
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }
}
